Skip to content

C++: Speed up Ssa::getAnUltimateDefinition - #22425

Open
MathiasVP wants to merge 5 commits into
github:mainfrom
MathiasVP:speed-up-get-an-ultimate-definition
Open

C++: Speed up Ssa::getAnUltimateDefinition#22425
MathiasVP wants to merge 5 commits into
github:mainfrom
MathiasVP:speed-up-get-an-ultimate-definition

Conversation

@MathiasVP

Copy link
Copy Markdown
Contributor

For a long time we've had an implementation of Ssa::getAnUltimateDefinition which is pretty much just a total copy/paste from the other languages, and the only use we've have for it has been when implementing iterator flow in SSA.

However, in 150d0a7 we started using it in FlowSummaryImpl.qll as well. And it turns out this predicate now performs poorly on a single DCA project (I guess maybe the predicate was magic'd prior to this change? I didn't actually check).

I don't expect that there's anything wrong with the predicate, and it's probably more likely that this project just has some crazy pattern somewhere.

With that said, it's quite simple to speed up the uses we have by doing an initial pruning phase.

  1. FlowSummaryImpl.qll is the simplest case since we have some ready bounds for one of th end-points (i.e., the ultimate definition).
  2. The iterator flow one is slightly more complicated since the "step" we're taking a transitive closure over consists of (among other things) a call to getAnUltimateDefinition. So for each iteration we have to provide a bound for the end-point, and that bound depends on the pruning we've done so far. This all leads to some fun recursion 🙈. I think it's all working well, though!

Before:

[2026-08-25 14:32:13] Evaluated non-recursive predicate SsaImpl::Definition.getAnUltimateDefinition/0#dispred#64b05bcd@4257f8rj in 36749ms (size: 947368939).
Evaluated relational algebra for predicate SsaImpl::Definition.getAnUltimateDefinition/0#dispred#64b05bcd@4257f8rj with tuple counts:
           429707   ~1%    {2} r1 = SCAN SsaImpl::SsaImpl::Definition#7e130722 OUTPUT In.0, In.0
                       
        947393511   ~1%    {2} r2 = `#SsaImpl::Definition.getAPhiInputOrPriorDefinition/0#dispred#e5e7cf53Plus#swapped` UNION r1
                           {2}    | AND NOT SsaImpl::SsaImpl::TPhiNode#58476d59_2#antijoin_rhs(FIRST 1)
        947369105   ~2%    {2}    | SCAN OUTPUT In.1, In.0
                           return r2

[2026-08-25 14:32:18] Evaluated non-recursive predicate FlowSummaryImpl::Input2::SourceSinkReportingElement.getCallable/0#dispred#14338d9c@166b76aa in 37ms (size: 8221).
Evaluated relational algebra for predicate FlowSummaryImpl::Input2::SourceSinkReportingElement.getCallable/0#dispred#14338d9c@166b76aa with tuple counts:
          7204   ~0%    {2} r1 = JOIN FlowSummaryImpl::Input2::SourceSinkReportingElement#5f9b62cc WITH `FlowSummaryImpl::Input2::getFunctionFromType/1#69f77c8e` ON FIRST 1 OUTPUT Lhs.0, Rhs.1
                    
          1016   ~0%    {2} r2 = JOIN FlowSummaryImpl::Input2::SourceSinkReportingElement#5f9b62cc WITH `FlowSummaryImpl::Input2::getFunctionFromExpr/1#f5cd0a4f` ON FIRST 1 OUTPUT Lhs.0, Rhs.1
                    
        441675   ~5%    {2} r3 = JOIN `Instruction::Instruction.getUnconvertedResultExpression/0#dispred#d46d1df3_10#join_rhs` WITH FlowSummaryImpl::Input2::SourceSinkReportingElement#5f9b62cc ON FIRST 1 OUTPUT Lhs.1, Lhs.0
        511564   ~0%    {2}    | JOIN WITH `Operand::Operand.getDef/0#dispred#a70e8079_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1
        139726   ~4%    {2}    | JOIN WITH `SsaImpl::Definition.getAUse/0#dispred#97e30a5e_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1
        152420   ~2%    {2}    | JOIN WITH `SsaImpl::Definition.getAnUltimateDefinition/0#dispred#64b05bcd` ON FIRST 1 OUTPUT Rhs.1, Lhs.1
        146731   ~4%    {2}    | JOIN WITH project#SsaImpl::DirectExplicitDefinition#6c37db61 ON FIRST 1 OUTPUT Lhs.0, Lhs.1
        106091   ~0%    {2}    | JOIN WITH `SsaImpl::ExplicitDefinition.getAssignedInstruction/0#dispred#2b7f8f44` ON FIRST 1 OUTPUT Rhs.1, Lhs.1
         43326   ~0%    {2}    | JOIN WITH Instruction::StoreInstruction#ae96f30c ON FIRST 1 OUTPUT Lhs.0, Lhs.1
         43326   ~0%    {2}    | JOIN WITH `Instruction::CopyInstruction.getSourceValue/0#dispred#991471be` ON FIRST 1 OUTPUT Rhs.1, Lhs.1
         33256   ~7%    {2}    | JOIN WITH `Instruction::Instruction.getUnconvertedResultExpression/0#dispred#d46d1df3` ON FIRST 1 OUTPUT Rhs.1, Lhs.1
             1   ~0%    {2}    | JOIN WITH `FlowSummaryImpl::Input2::getFunctionFromExpr/1#f5cd0a4f` ON FIRST 1 OUTPUT Lhs.1, Rhs.1
                    
          8221   ~1%    {2} r4 = r1 UNION r2 UNION r3
                        return r4

After:

Pipeline base for SsaImpl::GetAnUltimateDefinition<FlowSummaryImpl::Input2::GetAnUltimateDefinitionInput>::fwd/1#194007e7@f4033wso was evaluated in 1 iterations totaling 0ms (delta sizes total: 45).
                return `project#FlowSummaryImpl::Input2::isRelevantUltimateDefinition/2#056df527`

Pipeline standard for SsaImpl::GetAnUltimateDefinition<FlowSummaryImpl::Input2::GetAnUltimateDefinitionInput>::fwd/1#194007e7@f4033wso was evaluated in 1 iterations totaling 0ms (delta sizes total: 1).
        12  ~0%    {1} r1 = JOIN `SsaImpl::GetAnUltimateDefinition<FlowSummaryImpl::Input2::GetAnUltimateDefinitionInput>::fwd/1#194007e7#prev_delta` WITH `SsaImpl::getAPhiInputOrPriorDefinition/1#b4a967ca_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1
         1  ~0%    {1}    | AND NOT `SsaImpl::GetAnUltimateDefinition<FlowSummaryImpl::Input2::GetAnUltimateDefinitionInput>::fwd/1#194007e7#prev`(FIRST 1)
                   return r1

[2026-08-25 14:34:44] Evaluated non-recursive predicate SsaImpl::GetAnUltimateDefinition<FlowSummaryImpl::Input2::GetAnUltimateDefinitionInput>::step/2#882d6515@28fe1bti in 0ms (size: 12).
Evaluated relational algebra for predicate SsaImpl::GetAnUltimateDefinition<FlowSummaryImpl::Input2::GetAnUltimateDefinitionInput>::step/2#882d6515@28fe1bti with tuple counts:
        13  ~0%    {2} r1 = JOIN `SsaImpl::GetAnUltimateDefinition<FlowSummaryImpl::Input2::GetAnUltimateDefinitionInput>::fwd/1#194007e7` WITH `SsaImpl::getAPhiInputOrPriorDefinition/1#b4a967ca` ON FIRST 1 OUTPUT Rhs.1, Lhs.0
        12  ~0%    {2}    | JOIN WITH `SsaImpl::GetAnUltimateDefinition<FlowSummaryImpl::Input2::GetAnUltimateDefinitionInput>::fwd/1#194007e7` ON FIRST 1 OUTPUT Lhs.0, Lhs.1
                   return r1

[2026-08-25 14:34:44] Evaluated non-recursive predicate boundedFastTC:SsaImpl::GetAnUltimateDefinition<FlowSummaryImpl::Input2::GetAnUltimateDefinitionInput>::step/2#882d6515:project#FlowSummaryImpl::Input2::isRelevantUltimateDefinition/2#056df527@c1ac78fm in 0ms (size: 67).
[2026-08-25 14:34:44] Evaluated non-recursive predicate SsaImpl::GetAnUltimateDefinition<FlowSummaryImpl::Input2::GetAnUltimateDefinitionInput>::getAnUltimateDefinition/1#c3385f4f@174c4fok in 0ms (size: 112).
Evaluated relational algebra for predicate SsaImpl::GetAnUltimateDefinition<FlowSummaryImpl::Input2::GetAnUltimateDefinitionInput>::getAnUltimateDefinition/1#c3385f4f@174c4fok with tuple counts:
         45   ~0%    {2} r1 = SCAN `project#FlowSummaryImpl::Input2::isRelevantUltimateDefinition/2#056df527` OUTPUT In.0, In.0
                 
         67   ~1%    {2} r2 = JOIN `boundedFastTC:SsaImpl::GetAnUltimateDefinition<FlowSummaryImpl::Input2::GetAnUltimateDefinitionInput>::step/2#882d6515:project#FlowSummaryImpl::Input2::isRelevantUltimateDefinition/2#056df527` WITH `project#FlowSummaryImpl::Input2::isRelevantUltimateDefinition/2#056df527` ON FIRST 1 OUTPUT Lhs.1, Lhs.0
                 
        112   ~3%    {2} r3 = r1 UNION r2
                     return r3


[2026-08-25 14:34:44] Evaluated non-recursive predicate FlowSummaryImpl::Input2::SourceSinkReportingElement.getCallable/0#dispred#14338d9c@2bd0296f in 12ms (size: 8221).
Evaluated relational algebra for predicate FlowSummaryImpl::Input2::SourceSinkReportingElement.getCallable/0#dispred#14338d9c@2bd0296f with tuple counts:
          7204   ~0%    {2} r1 = JOIN FlowSummaryImpl::Input2::SourceSinkReportingElement#5f9b62cc WITH `FlowSummaryImpl::Input2::getFunctionFromType/1#69f77c8e` ON FIRST 1 OUTPUT Lhs.0, Rhs.1
                    
          1016   ~0%    {2} r2 = JOIN FlowSummaryImpl::Input2::SourceSinkReportingElement#5f9b62cc WITH `FlowSummaryImpl::Input2::getFunctionFromExpr/1#f5cd0a4f` ON FIRST 1 OUTPUT Lhs.0, Rhs.1
                    
        441675   ~0%    {2} r3 = JOIN `Instruction::Instruction.getUnconvertedResultExpression/0#dispred#d46d1df3_10#join_rhs` WITH FlowSummaryImpl::Input2::SourceSinkReportingElement#5f9b62cc ON FIRST 1 OUTPUT Lhs.1, Lhs.0
        511564   ~6%    {2}    | JOIN WITH `Operand::Operand.getDef/0#dispred#a70e8079_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1
        139726   ~5%    {2}    | JOIN WITH `SsaImpl::Definition.getAUse/0#dispred#97e30a5e_10#join_rhs` ON FIRST 1 OUTPUT Rhs.1, Lhs.1
             1   ~0%    {2}    | JOIN WITH `SsaImpl::GetAnUltimateDefinition<FlowSummaryImpl::Input2::GetAnUltimateDefinitionInput>::getAnUltimateDefinition/1#c3385f4f` ON FIRST 1 OUTPUT Rhs.1, Lhs.1
             1   ~0%    {2}    | JOIN WITH `FlowSummaryImpl::Input2::isRelevantUltimateDefinition/2#056df527` ON FIRST 1 OUTPUT Lhs.1, Rhs.1
                    
          8221   ~1%    {2} r4 = r1 UNION r2 UNION r3
                        return r4

@github-actions github-actions Bot added the C++ label Aug 25, 2026
@MathiasVP MathiasVP added the no-change-note-required This PR does not need a change note label Aug 25, 2026
@MathiasVP
MathiasVP marked this pull request as ready for review August 25, 2026 16:45
@MathiasVP
MathiasVP requested a review from a team as a code owner August 25, 2026 16:45
Copilot AI balanced review requested due to automatic review settings August 25, 2026 16:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Optimizes C++ SSA ultimate-definition traversal by pruning searches to relevant definitions.

Changes:

  • Adds a bounded, configurable ultimate-definition module.
  • Applies it to flow summaries and iterator flow.
  • Preserves the existing unrestricted API.
Show a summary per file
File Description
SsaImpl.qll Adds optimized SSA traversal.
DataFlowUtil.qll Exposes the new module.
DataFlowPrivate.qll Optimizes iterator flow traversal.
FlowSummaryImpl.qll Restricts traversal to callable definitions.

Review details

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImpl.qll Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C++ no-change-note-required This PR does not need a change note

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants